package com.mqtt.ctwingmqtt.controller;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ctg.ag.sdk.biz.AepDeviceCommandClient;
import com.ctg.ag.sdk.biz.aep_device_command.CreateCommandRequest;
import com.ctg.ag.sdk.biz.aep_device_command.CreateCommandResponse;
import com.mqtt.ctwingmqtt.domain.BatchResult1;
import com.mqtt.ctwingmqtt.domain.BatchResultEntry;
import com.mqtt.ctwingmqtt.domain.CtwEntity;
import com.mqtt.ctwingmqtt.domain.ResponseResult;
import com.mqtt.ctwingmqtt.domain.dto.CtwMssageDto;
import com.mqtt.ctwingmqtt.domain.dto.CtwNBMssageDto;
import com.mqtt.ctwingmqtt.domain.entity.*;
import com.mqtt.ctwingmqtt.security.utils.SecurityUtils;
import com.mqtt.ctwingmqtt.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.mqtt.ctwingmqtt.domain.entity.NbHouseholdValves;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;


@Api(value = "ctw接口")
@RestController
@RequestMapping("/ctw")
@RequiredArgsConstructor
@Slf4j
public class CtwingmqttController {
    @Autowired
    private CtwingService ctwingService;
    @Autowired
    private CtwEntity ctwEntity;
    @Autowired
    private NbHouseholdValvesService nbHouseholdValvesService;
    @Autowired
    private NbHouseholdValvesHistoryService nbHouseholdValesHistoryService;
    @Autowired
    private IIService iiservice;
    @Autowired
    private DeviceService deviceService;

    @ApiOperation("批量指令下发")
    @PostMapping("/valves")
    public ResponseResult batchSend(@RequestBody List<CtwMssageDto> messages) {
        List<BatchResultEntry> results = new ArrayList<>();
        // 遍历每个指令，收集结果
        for (CtwMssageDto msg : messages) {
            ResponseResult singleResult = send(msg);
            // 将结果封装为 BatchResultEntry
            BatchResultEntry entry = new BatchResultEntry(
                    msg.getDeviceAddress(), // 设备ID
                    singleResult.getCode(), // 状态码
                    singleResult.getMsg(),  // 消息描述
                    singleResult.getCode() == 200 // 是否成功
            );
            results.add(entry);
        }

        // 构建最终响应
        return ResponseResult.success(new BatchResult1(results));
    }
    public ResponseResult send(@RequestBody CtwMssageDto msg) {
        log.info("向测控一体化阀门发送消息：{}", msg);
        if(msg.getRemoteControlTarget() == null){
            msg.setRemoteControlTarget("01");
        }
        if (msg.getRemoteControlOpen() == null){
            msg.setRemoteControlOpen("AC04");
        }
        Boolean flag = false;
        // 构建客户端信息
        AepDeviceCommandClient client = AepDeviceCommandClient.newClient()
                .appKey(ctwEntity.getAppKey())
                .appSecret(ctwEntity.getAppSecret())
                .build();
        CreateCommandRequest request = new CreateCommandRequest();
        String masterKey = ctwEntity.getMasterKey();
        request.setParamMasterKey(masterKey);
        // 设置设备地址 按两位取反并补0到14位
        String deviceAddress = msg.getDeviceAddress();
        //String deviceAddress1 = convertAddress(deviceAddress);
        // 设置阀门开度
        Float valveOpen = msg.getValveOpen();
        String s = convertToHex(valveOpen);
        // 计算校验位从6846开始到校验位之前的数字进行二进制相加（不超过FFH）
        String input = "6846" + deviceAddress + "0406" + msg.getRemoteControlOpen() + "04" + msg.getRemoteControlTarget() + s;
        String CS = calculateCheckCode(input);
        // 构建完整的二进制数据
        String fullData = "FEFEFE" + input + CS + "16";


        //根据deviceAddress获取dtuName
        String dtuName = msg.getDtuId();

        // 构建请求体
        JSONObject jsonObject = new JSONObject();
        //ctwing中的设备id当前代表的是集中器的id，在ctwing平台中是设备的id
        jsonObject.put("deviceId", dtuName);
        //发送者名称
        jsonObject.put("operator", "ceebic");
        jsonObject.put("productId", ctwEntity.getProductId());
        jsonObject.put("level", 1);
        jsonObject.put("ttl", 864000);
        JSONObject content = new JSONObject();
        //1：字符串  2：十六进制
        content.put("dataType", 2);
        content.put("payload", fullData);

        jsonObject.put("content", content);

        // 设置请求体
        request.setBody(jsonObject.toString().getBytes());

        CreateCommandResponse response = null;
        try {
            // 发送请求
            response = client.CreateCommand(request);
        } catch (Exception e) {
            // 处理异常
            log.error("发送指令时发生异常", e);
            return ResponseResult.error(-1, "发送指令时发生异常");
        }

        // 处理响应
        String message = new String(response.getBody());
        // 解析响应体
        JSONObject object = JSON.parseObject(message);
        System.out.println(object);
        Object o = object.get("code");
        String o1 = (String) object.get("msg");
        int o2 = (int) o;
        //传入设备id，发送指令，回复数据，当前用户名
        String username = SecurityUtils.getCurrentUsername();
        // 解析result对象
        JSONObject result = object.getJSONObject("result");
        //解析响应体的指令id
        String commandId = "0";
        //解析响应体的产品id和设备id
        Integer productId = 0;
        String deviceId = "0";
        // 如果code为0则表示发送成功
        if (object.containsKey("code") && Integer.parseInt(o.toString()) == 0) {
            flag = true;
            //解析响应体的指令id
            commandId = result.getString("commandId");
            //解析响应体的产品id和设备id
            productId = result.getInteger("productId");
            deviceId = result.getString("deviceId");

        }
        ctwingService.addMessage(msg.getDeviceAddress(), fullData,o1,username,flag,commandId,productId,deviceId,masterKey);
        if (!flag) {
            return ResponseResult.error(deviceAddress,o2, o1);
        }
        //需要返回的设备地址deviceAddress
        client.shutdown();
        return ResponseResult.successs(deviceAddress,o1);
    }

    @ApiOperation("指令分页查询")
    @GetMapping("/commandPage")
    public ResponseResult commandPage(@RequestParam(defaultValue = "1") Long pageNum,
                                      @RequestParam(defaultValue = "1000") Long pageSize,
                                      String deviceAddress) {
        return ResponseResult.success(ctwingService.commandPage(pageNum, pageSize, deviceAddress ));
    }

    @ApiOperation("NB批量下发指令")
    @PostMapping("/nbvalves")
    public ResponseResult nbvalves(@RequestBody List<CtwNBMssageDto> messages) {
        List<BatchResultEntry> results = new ArrayList<>();
        // 遍历每个指令，收集结果
        for (CtwNBMssageDto msg : messages) {
            //获取传入的设备地址在imei表中查询对应的设备id
            String address = msg.getDeviceAddress();
            String deviceAddress=ctwingService.getdeviceId(address);
            if (deviceAddress==null){
                return ResponseResult.error(405,"设备imei未配置，请先配置imei");
            }
            msg.setDeviceAddress(deviceAddress);
            ResponseResult singleResult = NBsend(msg);
            // 将结果封装为 BatchResultEntry
            BatchResultEntry entry = new BatchResultEntry(
                    // 设备ID
                    address,
                    // 状态码
                    singleResult.getCode(),
                    // 消息描述
                    singleResult.getMsg(),
                    // 是否成功
                    singleResult.getCode() == 200
            );
            results.add(entry);
        }
        // 构建最终响应
        return ResponseResult.success(new BatchResult1(results));
    }

    private ResponseResult NBsend(CtwNBMssageDto msg) {
        if(msg.getValveOpen()==null){
            msg.setValveOpen(101F);
        }
        if(msg.getUploadPeriod()==null){
            msg.setUploadPeriod("0");
        }
        else {
            //传入小时转为分钟
            msg.setUploadPeriod(String.valueOf(Integer.parseInt(msg.getUploadPeriod())*60));
        }
        //拿到设备地址查询产品表拿到对应的masterKey和产品id
        String deviceId = msg.getDeviceAddress();
        //根据deviceId查询对应的deviceaddress
        String deviceAddress = iiservice.getdeviceAddress(deviceId);
        Map<Integer,String> map=deviceService.getmp(deviceAddress);
        String masterKey = map.get("masterKey");
        String productId1 = map.get("productId");
        Boolean flag = false;
        // 构建客户端信息
        AepDeviceCommandClient client = AepDeviceCommandClient.newClient()
                .appKey(ctwEntity.getAppKey())
                .appSecret(ctwEntity.getAppSecret())
                .build();
        CreateCommandRequest request = new CreateCommandRequest();
        request.setParamMasterKey(masterKey);
        // 构建请求体
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("deviceId", deviceId);
        //发送者名称
        jsonObject.put("operator", "ceebic");
        jsonObject.put("productId", productId1);
        jsonObject.put("level", 1);
        jsonObject.put("ttl", 864000);
        //构造下发指令
        JSONObject content = new JSONObject();
        content.put("dataType", 1);
        Float valveOpen = msg.getValveOpen();
        int open= Math.round(valveOpen);
        //构造平台下发的指令
        String fullData = "\""+ "cmd="+3 + "," + open + ","
                + 11 + "," + msg.getUploadPeriod() + "," + 0 + ","
                + 0 + "," + 101 + "," + 101 +"\"";
        content.put("payload",fullData);
        jsonObject.put("content", content);
        //设置请求体
        request.setBody(jsonObject.toString().getBytes());
        CreateCommandResponse response = null;
        try {
            // 发送请求
            response = client.CreateCommand(request);
        } catch (Exception e) {
            // 处理异常
            log.error("发送指令时发生异常", e);
            return ResponseResult.error(-1, "发送指令时发生异常");
        }

        // 处理响应
        String message = new String(response.getBody());
        // 解析响应体
        JSONObject object = JSON.parseObject(message);
        System.out.println(object);
        Object o = object.get("code");
        String o1 = (String) object.get("msg");
        int o2 = (int) o;
        //传入设备id，发送指令，回复数据，当前用户名
        String username = SecurityUtils.getCurrentUsername();
        // 解析result对象
        JSONObject result = object.getJSONObject("result");
        //解析响应体的指令id
        String commandId = "0";
        //解析响应体的产品id和设备id
        Integer productId = 0;
        // 如果code为0则表示发送成功
        if (object.containsKey("code") && Integer.parseInt(o.toString()) == 0) {
            flag = true;
            //解析响应体的指令id
            commandId = result.getString("commandId");
            //解析响应体的产品id和设备id
            productId = result.getInteger("productId");
            deviceId = result.getString("deviceId");

        }
        ctwingService.addMessage(deviceId,fullData,o1,username,flag,commandId,productId,deviceId,masterKey);
        if (!flag) {
            return ResponseResult.error(deviceId,o2, o1);
        }
        //需要返回的设备地址deviceAddress
        client.shutdown();
        return ResponseResult.successs(deviceId,o1);
    }


    @ApiOperation("数据上报")
    @PostMapping("/dataReport")
    @Transactional
    public Map<String, Object> handleNBHouseholdValvesData() {
        // 打印日志
        log.info("CTWing订阅消息推送NB户用阀门");
        HashMap<String, Object> map = new HashMap<>();

        try {
            // 拿到线程中的ServletRequestAttributes对象，这个对象包含了当前http请求的一些信息
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            // 判断是否为空，如果为空则返回500状态码
            if (requestAttributes == null) {
                map.put("http", 500);
                return map;
            }
            // 再次拿到请求对象request放到HttpServletRequest中
            HttpServletRequest request = requestAttributes.getRequest();
            // 定义一个StringBuilder对象，用来拼接字符串
            StringBuilder buffer = new StringBuilder();
            // 获取输入流
            InputStream is = request.getInputStream();
            InputStreamReader reader = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(reader);
            String s = "";
            while ((s = br.readLine()) != null) {
                buffer.append(s);
            }
            // 转换为json对象
            String Result = buffer.toString();
            JSONObject jsonObject = JSON.parseObject(Result);
            System.out.println("接收推送数据是:" + Result);
            // 判断是否为上报数据
            if (!jsonObject.get("messageType").equals("dataReport")) {
                return null;
            }
            // 获取设备中的设备id转为string格式
            String deviceId = jsonObject.get("deviceId").toString();
            // 根据设备id查询对应的地址
            String deviceAddress =iiservice.getdeviceAddress(deviceId);
            if(deviceAddress == null){
                //如果上传的设备id没有对应的地址，则返回null
                return null;
            }
            //根据地址查询对应的产品名称
            String productName = deviceService.getProductName(deviceAddress);
            //String iemi = jsonObject.get("IMEI").toString();
            // 获取时间戳记录数据上报时间
            long timestamp = jsonObject.getLong("timestamp");
            String appData = (JSON.parseObject(jsonObject.get("payload").toString()).get("APPdata").toString());
            // 进行base64解码转换为字符byte，传过来的数据为类似My81MC81MC4zLzI0LjkvMjQuOS8zMTEvMy42Lzc4Njg4LzE0LzEvQQ==
            // 进行base64解码字符串为
            // 工作模式/给定工作量/当前开度/温度 /温度 /电机电流mA/电池电压V/工作时间/信号强度/st1/st2
            // 3     /50      /50.5  /25.9 /25.9 /0        /3.5    /21    /20     /1  /A
            byte[] decode = Base64.getDecoder().decode(appData);
            // 转换为字符串
            String decodeString = new String(decode);
            // 定义对应实体类的类型，用字符串分割分别存储每一位的数据
            // 工作模式第0位
            Integer workMode = Integer.parseInt(decodeString.split("/")[0]);
            // 给定控制量第1位
            float givenControl = Float.parseFloat(decodeString.split("/")[1]);
            // 当前开度第2位
            float currentOpen = Float.parseFloat(decodeString.split("/")[2]);
            // 温度1第3位
            float temperature1 = Float.parseFloat(decodeString.split("/")[3]);
            // 温度2第4位
            float temperature2 = Float.parseFloat(decodeString.split("/")[4]);
            // 电机电流mA第5位
            float motorCurrent = Float.parseFloat(decodeString.split("/")[5]);
            // 电池电压V第6位
            float batteryVoltage = Float.parseFloat(decodeString.split("/")[6]);
            // 工作时间min第7位
            Integer workTime = Integer.parseInt(decodeString.split("/")[7]);
            // 信号强度dBm第8位
            Integer signalStrength = Integer.parseInt(decodeString.split("/")[8]);
            // ST1状态第9位
            String st1 = decodeString.split("/")[9];
            // ST2状态第10位
            String st2 = decodeString.split("/")[10];

            // 实时数据
            // 先查询实时数据表中有没有数据，根据设备id构建查询条件
            LambdaQueryWrapper<NbHouseholdValves> temperatureWrapper = Wrappers.lambdaQuery();
            temperatureWrapper.eq(NbHouseholdValves::getDeviceAddress, deviceAddress);
            // 根据id获取到实时榜单的数据
            NbHouseholdValves nbHouseholdValves = nbHouseholdValvesService.getOne(temperatureWrapper);
            // 判断是否为空如果为空就创建新的实时榜单，如果不为空就更新最新的数据
            if (nbHouseholdValves == null) {
                nbHouseholdValves = new NbHouseholdValves();
                // 设置设备ID
                nbHouseholdValves.setDeviceAddress(deviceAddress);
                // 设置工作模式
                nbHouseholdValves.setWorkMode(workMode);
                // 设置给定控制量
                nbHouseholdValves.setGivenControl(givenControl);
                // 设置当前开度
                nbHouseholdValves.setCurrentOpen(currentOpen);
                // 设置温度1
                nbHouseholdValves.setTemperature1(temperature1);
                // 设置温度2
                nbHouseholdValves.setTemperature2(temperature2);
                // 设置电机电流
                nbHouseholdValves.setMotorCurrent(motorCurrent);
                // 设置电池电压
                nbHouseholdValves.setBatteryVoltage(batteryVoltage);
                // 设置工作时间
                nbHouseholdValves.setWorkTime(workTime);
                // 设置信号强度
                nbHouseholdValves.setSignalStrength(signalStrength);
                // 设置状态
                nbHouseholdValves.setStatus(st1);
                nbHouseholdValves.setStatus2(st2);
                // 设置数据上报时间
                nbHouseholdValves.setReportTime(new Date(timestamp));
                // 设置创建时间
                nbHouseholdValves.setCreateTime(new Date());
                //设置产品名称
                nbHouseholdValves.setProductName(productName);
                //设置创建时间数据上报时间更新时间
                nbHouseholdValves.setCreateTime(new java.sql.Timestamp(System.currentTimeMillis()));
                nbHouseholdValves.setReportTime(new java.sql.Timestamp(System.currentTimeMillis()));
                nbHouseholdValves.setUpdateTime(new java.sql.Timestamp(System.currentTimeMillis()));
                // 保存新的对象
                nbHouseholdValvesService.save(nbHouseholdValves);
            } else {
                // 不为空，只设置最新的数据
                // 设置工作模式
                nbHouseholdValves.setWorkMode(workMode);
                // 设置给定控制量
                nbHouseholdValves.setGivenControl(givenControl);
                // 设置当前开度
                nbHouseholdValves.setCurrentOpen(currentOpen);
                // 设置温度1
                nbHouseholdValves.setTemperature1(temperature1);
                // 设置温度2
                nbHouseholdValves.setTemperature2(temperature2);
                // 设置电机电流
                nbHouseholdValves.setMotorCurrent(motorCurrent);
                // 设置电池电压
                nbHouseholdValves.setBatteryVoltage(batteryVoltage);
                // 设置工作时间
                nbHouseholdValves.setWorkTime(workTime);
                // 设置信号强度
                nbHouseholdValves.setSignalStrength(signalStrength);
                // 设置状态
                nbHouseholdValves.setStatus(st1);
                nbHouseholdValves.setStatus2(st2);
                nbHouseholdValves.setReportTime(new java.sql.Timestamp(System.currentTimeMillis()));
                nbHouseholdValvesService.updateByAddress(nbHouseholdValves);
            }

            // 历史数据
                NbHouseholdValvesHistory nbHouseholdValvesHistory = new NbHouseholdValvesHistory();
                // 设置设备ID
                nbHouseholdValvesHistory.setDeviceAddress(deviceAddress);
                // 设置工作模式
                nbHouseholdValvesHistory.setWorkMode(workMode);
                // 设置给定控制量
                nbHouseholdValvesHistory.setGivenControl(givenControl);
                // 设置当前开度
                nbHouseholdValvesHistory.setCurrentOpen(currentOpen);
                // 设置温度1
                nbHouseholdValvesHistory.setTemperature1(temperature1);
                // 设置温度2
                nbHouseholdValvesHistory.setTemperature2(temperature2);
                // 设置电机电流
                nbHouseholdValvesHistory.setMotorCurrent(motorCurrent);
                // 设置电池电压
                nbHouseholdValvesHistory.setBatteryVoltage(batteryVoltage);
                // 设置工作时间
                nbHouseholdValvesHistory.setWorkTime(workTime);
                // 设置信号强度
                nbHouseholdValvesHistory.setSignalStrength(signalStrength);
                // 设置状态
                nbHouseholdValvesHistory.setStatus(st1);
                nbHouseholdValvesHistory.setStatus2(st2);
                // 设置数据上报时间
                nbHouseholdValvesHistory.setReportTime(new java.sql.Timestamp(System.currentTimeMillis()));
                // 设置创建时间
                nbHouseholdValvesHistory.setCreateTime(new java.sql.Timestamp(System.currentTimeMillis()));
                //设置产品名称
                nbHouseholdValvesHistory.setProductName(productName);
                nbHouseholdValesHistoryService.save(nbHouseholdValvesHistory);

        } catch (IOException e) {
            log.error("处理NB户用阀门数据时发生错误", e);
            map.put("http", 500);
            return map;
        }
        map.put("http", 200);
        return map;
    }



    @ApiOperation("取消指令")
    @PutMapping("/cancelCommand")
    public ResponseResult cancelCommand(@RequestBody Command command){
        Boolean b = ctwingService.cancelCommand(command);
        return ResponseResult.success(b);
    }
    public static String calculateCheckCode(String hexData) {
        // 1. 验证输入是否为有效十六进制
        if (!hexData.matches("[0-9a-fA-F]+")) {
            throw new IllegalArgumentException("输入必须是有效的十六进制字符串");
        }

        // 2. 将十六进制字符串转换为字节数组
        byte[] bytes = hexStringToByteArray(hexData);

        // 3. 累加所有字节的值，忽略溢出（取低8位）
        int sum = 0;
        for (byte b : bytes) {
            sum += (b & 0xFF); // 将字节转换为无符号整数
        }
        int checkCode = sum & 0xFF; // 取低8位

        // 4. 将校验码转换为两位大写十六进制字符串
        return String.format("%02X", checkCode);
    }
    private static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

    /**
     * 10进制转16进制
     * @param num
     * @return
     */
    public static String convertToHex(float num) {
        int result = Math.round(num * 10);
        return String.format("%04X", result);
    }

    /**
     * 地址转换
     * @param address
     * @return
     */
    private static String convertAddress(String address) {
        if (address == null || address.isEmpty()) {
            throw new IllegalArgumentException("地址不能为空");
        }

        // 按2位分割字符串
        int length = address.length();
        StringBuilder convertedAddress = new StringBuilder();

        // 分割为每两位的块，并逆序排列
        for (int i = length - 2; i >= 0; i -= 2) {
            String pair = address.substring(i, i + 2);
            convertedAddress.append(pair);
        }

        // 处理奇数长度的情况（最后一位单独处理）
        if (length % 2 != 0) {
            char lastChar = address.charAt(0); // 取第一位（如果总长度为奇数）
            convertedAddress.append(lastChar);
        }

        // 将结果转换为字符串，并补足到14位
        String result = convertedAddress.toString();
        if (result.length() > 14) {
            result = result.substring(0, 14);
        } else {
            result = String.format("%-" + 14 + "s", result).replace(' ', '0');
        }

        return result;
    }



}
